#include <dalelib/alife/geneticalgorithm.h>

namespace dalelib
{

//********************************************************************
Genotype::Genotype() { }
Genotype::~Genotype() { }
void Genotype::crossover(void* _Parent1,void* _Parent2) { }
void Genotype::mutate(const float _MutationRate) { }
void Genotype::createRandom(const int _Size) { }
void Genotype::validate() { }
void Genotype::save(const string _FileName) { }
void Genotype::load(const string _FileName) { }

//********************************************************************
DefaultGenotype::DefaultGenotype()
	: _lower_limit(0.f)
	, _upper_limit(1.f)
	, _mutation_size(1.f)
{ }

DefaultGenotype::~DefaultGenotype()
{ }

void DefaultGenotype::crossover(void* _Parent1,void* _Parent2)
{
	DefaultGenotype* p1 = (DefaultGenotype*)_Parent1;
	DefaultGenotype* p2 = (DefaultGenotype*)_Parent2;
//		halt_assert(_Parent1._dna.size()==_dna.size(),"genotype parent 1 is wrong size\n");
	int cp1 = rand()%_dna.size();
	int cp2 = rand()%_dna.size(); // 2 point crossover
	if(cp1>cp2) { int temp = cp1; cp1 = cp2; cp2 = temp; } // sort crossover points
	for(int i=0; i<_dna.size(); ++i)
	{
		_dna[i] = ( i<cp1 || i>=cp2 ) ? p1->_dna[i] : p2->_dna[i];
	}
}

void DefaultGenotype::mutate(const float _MutationRate)
{
	for(unsigned int i=0; i<_dna.size(); ++i)
	{
		if(RAND<_MutationRate) _dna[i] += GRRAND(3)*_mutation_size;
	}
	validate();
}

void DefaultGenotype::createRandom(const int _Length)
{
	_dna.resize(_Length);
	for(unsigned int i=0; i<_dna.size(); ++i)
	{
		_dna[i] = _lower_limit + RAND*(_upper_limit-_lower_limit);
	}
}

void DefaultGenotype::validate()
{
	for(unsigned int i=0; i<_dna.size(); ++i)
	{
		if( _dna[i]<_lower_limit ) _dna[i] = _lower_limit;
		if( _dna[i]>_upper_limit ) _dna[i] = _upper_limit;
	}
}

void DefaultGenotype::save(const string _FileName)
{
//		cout << "Saving genotype file: " << _FileName << endl;
	ofstream myfile;
	myfile.open(_FileName.c_str(),fstream::out);
	myfile << _dna.size() << "    " << _fitness << endl;
	for(int i=0; i<_dna.size(); ++i) myfile << _dna[i] << " ";
	myfile << endl;
	myfile.close();
}

void DefaultGenotype::load(const string _FileName)
{
//		cout << "Loading genotype file: " << _FileName << endl;
	ifstream myfile;
	myfile.open(_FileName.c_str(),fstream::in);
	int len; float fitness;
	myfile >> len >> fitness;
	_dna.resize(len);
	for(int i=0; i<len; ++i) myfile >> _dna[i];
	myfile.close();
}

//********************************************************************
//GeneticAlgorithm<DefaultGenotype>::GeneticAlgorithm() { }

} // namespace dalelib
